<?php
/**
 *  WB_Identifier class
 *  Concepts: Delimiter, parts
 *  
 *  @author Jean-Lou Dupont
 *  @version @@package-version@@
 *  @package Identifier
 *  @category Identifier
 */

//{{include
require_once 'web-bloks/BaseClass/BaseClass.php';
//include}}

class WB_Identifier
 	extends WB_BaseClass
 {
 	/**
 	 * Default delimiter
 	 * @private
 	 */
 	static $_default_delimiter = '/';
	
	/**
	 * Default parts name
	 * @private
	 */
	static $_default_partsName = array( 'domain', 'sdomain' );
	
 	/**
 	 * Default delimiter character
 	 */
 	var $delimiter = null;

	/**
	 * Parts name
	 */
	var $partsName = null;
	
	/**
	 * Parts
	 */
	var $parts = array();
	
	/**
	 * Identifier
	 */
	var $identifier = null;
	
	/**
	 * Internal modified state
	 * @private
	 */
	var $_modified = true;
	
 	/**
 	 * Constructor
 	 * 
 	 * @param $class class of this object instance
 	 * @param $params parameters of this object
 	 */
 	public function __construct( $params = null )
	{
		parent::__construct( $params );
		
		$this->setDelimiter( self::$_default_delimiter );
		$this->setSchema( self::$_default_partsName );
	}

	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	// Inherited from BaseClass
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	/**
	 * From BaseClass
	 * 
	 * @return 
	 */
	public function getClassPath()
	{
		return 'web-bloks/Identifier';
	}

	/**
	 * getClassVersion
	 * 
	 * @return string version
	 */
	public function getClassVersion()
	{
		return '$Id: Identifier.php 171 2008-04-01 00:46:57Z jldupont $';
	}
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	// Defaults interface
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	/**
	 * Sets the default delimiter pattern for the whole class
	 * 
	 * @param $delimiter string
	 */
	public static function setDefaultDelimiter( $delimiter )
	{
		self::$_default_delimiter = $delimiter;
	}
	/**
	 * Sets the default schema for the whole class
	 * 
	 * @param $schema array of strings
	 */
	public static function setDefaultSchema( $schema )
	{
		self::$_default_partsName = $schema;
	}
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	// VALIDATION
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	/**
	 * Validation
	 * This should be enhanced in derived classes.
	 * 
	 * @return $result Boolean
	 */
	public function validate()
	{
		return true;
	}
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	// Methods of this class
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	/**
	 * Sets the delimiter
	 * 
	 * @return $this
	 * @param $delimiter string
	 */
	public function setDelimiter( $delimiter )	
	{
		$this->delimiter = $delimiter;
		return $this;
	}
	/**
	 * Returns the delimiter
	 * 
	 * @return string $delimiter
	 */
	public function getDelimiter()
	{
		return $this->delimiter;
	}	
	/**
	 * Returns the array 'parts'
	 * 
	 * @return array $parts
	 */
	public function getParts()
	{
		return $this->parts;
	}	
	/**
	 * Returns the full identifier as a string
	 * 
	 * @return string
	 */
	public function get()
	{
		// if the identifier is already formatted, return it quick.
		if ( !$this->_modified )
			return $this->identifier;

		$this->identifier = implode( $this->delimiter, $this->parts );
		
		// reset the status flag.
		$this->_modified = false;
		
		return $this->identifier;		
	}
	/**
	 * Sets the identifier.
	 * Makes-up the $identifier through the provided $delimiter. 
	 * 
	 * Example1:
	 *  PartsName = { P1, P2 }
	 *  Delimiter = /
	 *  Identifier = A/B
	 *  $parts = { 'A', 'B' }
	 * 
	 * Example2:
	 *  PartsName = { P1, P2, P3 }
	 *  Delimiter = /
	 *  Identifier = A/B/C/D/E
	 *  $parts = { 'A', 'B', 'C', 'D/E' }
	 *  
	 * Example3:
	 *  PartsName = { P1, P2, P3 }
	 *  Delimiter = /
	 *  Identifier = A/B
	 *  $parts = { 'A', 'B' }
	 *  
	 * @return $this
	 * @param $identifier Object
	 * @throw Identifier_Exception
	 */
	public function set( $identifier )
	{
		// saves us some work IFF not modified later
		// by the other setter methods.
		$this->identifier = $identifier;
		
		$this->_modified = false;
		
		$parts = explode( $this->delimiter, $identifier );
		
		// start fresh
		$this->parts = array();
		
		foreach( $this->partsName as $index => &$partName )
		{
			// if $parts array is empty, then NULL
			// elements will fill the $this->parts array
			$part = array_shift( $parts );
			if ( $part === null )
				break;
			$this->parts[] = $part;
		}
		// if there are no more $this->partsName *but* the $parts
		// array is non-empty THEN re-group the remaining parts
		if ( !empty( $parts ) )
		{
			$lastPart = array_pop( $this->parts );
			array_unshift( $parts, $lastPart );
			$this->parts[] = implode( $this->delimiter, $parts );
		}
		
		return $this;
	}	
	/**
	 * Returns the schema
	 * 
	 * @return $schema array
	 */
	public function getSchema( )
	{
		return $this->partsName;
	}
	/**
	 * SetSchema
	 * 
	 * @return $this
	 * @param $schema Object
	 */
	public function setSchema( $schema )
	{
		$this->partsName = $schema;
		return $this;
	}

	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	// Wildcard Getter/Setter
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	/**
	 * Wildcard Getter
	 * 
	 * @return 
	 * @param $name Object
	 * @throws Identifier_Exception	 * 
	 */	
	public function __get( $partName )
	{
		if (!in_array( $partName, $this->partsName ))
			$this->throwException( 'invalid part name' );

		$index = array_search( $partName, $this->partsName );

		return $this->parts[ $index ];		
	}

	/**
	 * Wildcard Setter
	 * 
	 * @return $this
	 * @param $partName String
	 * @param $value Object
	 */
	public function __set( $partName, $value )
	{
		if (!in_array( $partName, $this->partsName ))
			$this->throwException( 'invalid part name' );
	
		$this->_modified = true;
		
		$index = array_search( $partName, $this->partsName );
		
		$this->parts[ $index ] = $value;
		
		return $this;
	}

	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	// UNIQUE ID helper
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	/**
	 * GenerateUID
	 * 
	 * @return $result String
	 */
	public static function generateUID()
	{
		
	}
	/**
	 * GetRemoteIP
	 * If running in CLI mode, then _SERVER['REMOTE_ADDR'] isn't
	 * available so we generate a fake IP; used for debug purposes mainly.
	 * 
	 * @return $ip String
	 */
	public static function getRemoteIP()
	{
		return isset( $_SERVER['REMOTE_ADDR'] ) ?
			$_SERVER['REMOTE_ADDR'] : '192.168.1.'.mt_rand( 1, 254 );
	}
	/**
	 * Pads an IP address with '0' in order
	 * to have each part of length 3.
	 * 
	 * @return $ip String
	 * @param $ip String
	 */	
	public static function specialFormatIP( &$ip )
	{
		$bits = explode( '.', $ip );

		$res = array_map( array('WB_Identifier', 'specialFormatPad' ) , $bits );		
		
		return implode( '.', $res );
	}
	/**
	 * specialFormatPad
	 * Pads an input with '0'
	 * 
	 * @return $result String
	 * @param $e string Input
	 */	
	protected static function specialFormatPad( &$e )
	{
		return (string) str_pad( $e, 3, '0', STR_PAD_LEFT );	
	}
 } // end class
